﻿namespace OpenComposite.Repository.Forms.TrackingMonitor
{
	using System;
	using System.CodeDom;
	using System.Collections.Generic;
	using System.ComponentModel;
	using System.ComponentModel.Design;
	using System.ComponentModel.Design.Serialization;
	using System.Data;
	using System.Data.SqlClient;
	using System.Drawing;
	using System.Globalization;
	using System.IO;
	using System.Linq;
	using System.Reflection;
	using System.Text;
	using System.Windows.Forms;
	using System.Workflow.ComponentModel;
	using System.Workflow.ComponentModel.Compiler;
	using System.Workflow.ComponentModel.Design;
	using System.Workflow.ComponentModel.Serialization;
	using System.Workflow.Runtime;
	using System.Workflow.Runtime.Tracking;
	using System.Xml;

	using OpenComposite.EII;

	using OpenComposite.Base;
	using OpenComposite.Base.Collections;
	using OpenComposite.Repository.Properties;
	using OpenComposite.Repository.Tracking;

	using WeifenLuo.WinFormsUI.Docking;
	using System.Diagnostics;
	using OpenComposite.EII.Designer.Workflow;
	using OpenComposite.Controls;

	public partial class TrackingMonitor : UserControl
	{
		#region Initialization

		public TrackingMonitor()
		{
			InitializeComponent();
			AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

			_processList = new TrackedProcessList();
			_processList.ShowWorkflow += new EventHandler<OpenComposite.Base.EventArgs<TrackedProcessInstance>>(_processList_ShowWorkflow);
			_activityList = new TrackedActivityList();
			_activityList.SelectActivity += new EventHandler<OpenComposite.Base.EventArgs<TrackedActivityInstance>>(_activityList_SelectActivity);
			_workflowView = new TrackingWorkflowView();
			_details = new TrackedActivityDetails();
			_details.LoadAssembly += new EventHandler<EventArgs<TrackedProcessInstance>>(_details_LoadAssembly);
			_businessObjectView = new TrackedBusinessObjects();

			_processList.Show(this.dockPanel1, DockState.DockLeft);
			_activityList.Show(_processList.Pane, DockAlignment.Bottom, 0.5);
			_workflowView.Show(this.dockPanel1, DockState.Document);

			dtpMinWfStart = new DateTimePickerEx();
			dtpMinWfStart.ValueChanged += new EventHandler(dtpMinWfStart_ValueChanged);
			ToolStripControlHost minWfStartHost = new ToolStripControlHost(dtpMinWfStart);
			dateTimeFilterToolStrip.Items.Insert(dateTimeFilterToolStrip.Items.IndexOf(tslblMinWfStart) + 1, minWfStartHost);

			dtpMaxWfStart = new DateTimePickerEx();
			dtpMaxWfStart.ValueChanged += new EventHandler(dtpMaxWfStart_ValueChanged);
			ToolStripControlHost maxWfStartHost = new ToolStripControlHost(dtpMaxWfStart);
			dateTimeFilterToolStrip.Items.Insert(dateTimeFilterToolStrip.Items.IndexOf(tslblMaxWfStart) + 1, maxWfStartHost);

			tscmbWfStatus.ComboBox.DataSource = StatusList;
			tscmbWfStatus.SelectedIndex = 0;

			string conn = Global.Data.GetTrackingConnection();
			if ( !string.IsNullOrEmpty(conn) ) {
				conn = Helpers.DecryptDecompressString(conn);
				_connectionString = conn;
				_sqlConn = new SqlConnection(conn);
			}
		}

		void dtpMinWfStart_ValueChanged(object sender, EventArgs e)
		{
			dtpMaxWfStart.Checked = dtpMinWfStart.Checked;
		}

		void dtpMaxWfStart_ValueChanged(object sender, EventArgs e)
		{
			dtpMinWfStart.Checked = dtpMaxWfStart.Checked;
		}

		#endregion Initialization

		#region Public Members

		#region Events

		public event FormClosingEventHandler Close;

		#endregion Events

		#region Static Properties

		public static BindingListEx<WorkflowStatusEx> StatusList
		{
			get
			{
				BindingListEx<WorkflowStatusEx> list = new BindingListEx<WorkflowStatusEx>();

				list.Add(WorkflowStatusEx.All);
				list.Add(WorkflowStatusEx.Completed);
				list.Add(WorkflowStatusEx.Created);
				list.Add(WorkflowStatusEx.Running);
				list.Add(WorkflowStatusEx.Suspended);
				list.Add(WorkflowStatusEx.Terminated);

				return list;
			}
		}

		#endregion Static Properties

		#region Methods

		public void LoadInstances()
		{
			loadWorkflowInstances();
		}

		#endregion Methods

		#endregion Public Members

		#region Internal Members

		#region Methods

		internal void ShowOptions(bool preCheckOldConnection)
		{
			if ( preCheckOldConnection && !string.IsNullOrEmpty(_connectionString) ) {
				bool validConnection = true;
				using ( SqlConnection conn = new SqlConnection(_connectionString) ) {
					try {
						conn.Open();
					} catch ( SqlException sqlEx ) {
						MessageBox.Show(string.Format("There was an error connection to the database:{0}{1}",
							Environment.NewLine, sqlEx.Message), "SQL Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
						validConnection = false;
					}
				}
				if ( validConnection ) return;
			}
			using ( FormTrackingMonitorOptions options = new FormTrackingMonitorOptions() ) {
				if ( !string.IsNullOrEmpty(_connectionString) )
					options.ConnectionString = _connectionString;

				options.ShowDialog();
				if ( options.DialogResult == DialogResult.OK ) {
					_sqlConn = new SqlConnection(options.ConnectionString);
					_connectionString = options.ConnectionString;
					SqlConnectionStringBuilder connBuilder = new SqlConnectionStringBuilder(_connectionString);
					string stringToDb = Helpers.EncryptCompressString(connBuilder.ConnectionString);
					Global.Data.SetTrackingConnection(stringToDb);
				}
			}
		}

		#endregion Methods

		#endregion Internal Members

		#region Protected Members

		#region Methods

		protected override object GetService(Type serviceType)
		{
			if ( _surface != null )
				return _surface.GetService(serviceType);
			else
				return null;
		}

		#endregion Methods

		#endregion Protected Members

		#region Private Members

		#region Fields

		private BindingListEx<TrackedActivityInstance> _actInstances = new BindingListEx<TrackedActivityInstance>();
		private TrackedActivityList _activityList;
		private string _connectionString = null;
		private TrackedActivityDetails _details;
		private List<string> _ignoreDllResolve = new List<string>();
		private TrackingWorkflowLoader _loader = null;
		private TrackedProcessList _processList;
		private TrackedBusinessObjects _businessObjectView;
		private SqlConnection _sqlConn = null;
		private TrackingWorkflowDesignSurface _surface = null;
		private WorkflowView _view = null;
		private BindingListEx<TrackedProcessInstance> _wfInstances = new BindingListEx<TrackedProcessInstance>();
		private TrackingWorkflowView _workflowView;
		private DateTimePickerEx dtpMaxWfStart;
		private DateTimePickerEx dtpMinWfStart;

		#endregion Fields

		#region Event Handlers

		System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			AssemblyName assmName = new AssemblyName(args.Name);
			if ( assmName.Name == "OpenComposite.Core.XmlSerializers" ) return null;
			if ( assmName.Name == "OpenComposite.Workflow.XmlSerializers" ) return null;
			if ( assmName.Name == "OpenComposite.Shared.XmlSerializers" ) return null;
			if ( assmName.Name == "OpenComposite.Repository.XmlSerializers" ) return null;
			if ( assmName.Name == "OpenComposite.CompositeStudio.XmlSerializers" ) return null;
			if ( assmName.Name == "mscorlib.XmlSerializers" ) return null;
			if ( assmName.Name.StartsWith("System.") ) return null;

			try {
				Assembly assembly = Global.Data.GetWorkflowDll(args.Name);
				if ( assembly == null ) {
					assembly = openAssembly(args.Name, true, false);
				}
				if ( assembly != null ) Global.Data.UploadWorkflowDll(assembly);
				return assembly;
			} catch ( SqlException ) {
				return null;
			}
		}

		void _activityList_SelectActivity(object sender, EventArgs<TrackedActivityInstance> e)
		{
			selectActivity(e.Argument);
		}

		void _details_LoadAssembly(object sender, EventArgs<TrackedProcessInstance> e)
		{
			Assembly asm = openAssembly(e.Argument.Instance.WorkflowAssemblyName, false, true);

			if ( asm != null ) {
				Global.Data.UploadWorkflowDll(asm);
				showWorkflow(e.Argument);
			}
		}

		void _processList_ShowWorkflow(object sender, EventArgs<TrackedProcessInstance> e)
		{
			showWorkflow(e.Argument);
		}

		private void activityListToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( _activityList.Visible ) return;
			_activityList.Show(this.dockPanel1);
		}

		private void alwaysShowDocumentTabsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.dockPanel1.DocumentStyle = alwaysShowDocumentTabsToolStripMenuItem.Checked ? DocumentStyle.DockingWindow : DocumentStyle.DockingSdi;
			this.dockPanel1.Scale(new SizeF(1, 1));
		}

		private void detailsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			toggleDetails(detailsToolStripMenuItem.Checked);
		}

		private void businessObjectsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			toggleBobjView(businessObjectsToolStripMenuItem.Checked);
		}

		private void dgvActivityInstances_CellClick(object sender, DataGridViewCellEventArgs e)
		{
			if ( e.RowIndex < 0 ) return;
			TrackedActivityInstance item = _activityList.ActivityInstances.Rows[e.RowIndex].DataBoundItem as TrackedActivityInstance;
			if ( item == null ) return;
			selectActivity(item);
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			FormClosingEventHandler tmp = Close;
			if ( tmp != null ) {
				tmp(this, new FormClosingEventArgs(CloseReason.UserClosing, false));
			}
		}

		private void processListToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if ( _processList.Visible ) return;
			_processList.Show(this.dockPanel1);
		}

		private void tsbtnDetails_Click(object sender, EventArgs e)
		{
			toggleDetails(tsbtnDetails.Checked);
		}

		private void tsbtnShowBobjView_Click(object sender, EventArgs e)
		{
			toggleBobjView(tsbtnShowBobjView.Checked);
		}

		private void tsbtnOptions_Click(object sender, EventArgs e)
		{
			string oldConn = _connectionString;
			ShowOptions(false);
			if ( _connectionString != oldConn ) loadWorkflowInstances(false);
		}

		private void tsbtnRefresh_Click(object sender, EventArgs e)
		{
			loadWorkflowInstances();
		}

		private void tscmbWfStatus_SelectedIndexChanged(object sender, EventArgs e)
		{
		}

		private void tstxtWfName_KeyUp(object sender, KeyEventArgs e)
		{
		}

		#endregion Event Handlers

		#region Methods

		//Initializes the designer setting up the services, surface, and loader
		private void Initialize()
		{
			if ( _surface != null ) {
				ISelectionService selSvc = _surface.GetService<ISelectionService>();
				if ( selSvc != null ) {
					selSvc.SelectionChanged -= selectionService_SelectionChanged;
				}
				_surface.Dispose();
			}

			_loader = new TrackingWorkflowLoader();
			_surface = new TrackingWorkflowDesignSurface(new MemberCreationService());
			ISelectionService selectionService = _surface.GetService<ISelectionService>();
			if ( selectionService != null ) {
				selectionService.SelectionChanged += new EventHandler(selectionService_SelectionChanged);
			}
			WorkflowTheme.CurrentTheme.ReadOnly = false;
			WorkflowTheme.CurrentTheme.AmbientTheme.ShowConfigErrors = false;
			WorkflowTheme.CurrentTheme.ReadOnly = true;
		}

		void selectionService_SelectionChanged(object sender, EventArgs e)
		{
			ISelectionService selectionService = _surface.GetService<ISelectionService>();
			if ( selectionService != null ) {
				Activity selection = selectionService.PrimarySelection as Activity;
				if ( selection == null ) return;
				foreach ( DataGridViewRow row in _activityList.ActivityInstances.Rows ) {
					TrackedActivityInstance instance = row.DataBoundItem as TrackedActivityInstance;
					if ( instance == null ) continue;
					if ( instance.Name == selection.QualifiedName ) {
						row.Selected = true;
						_details.LoadDetails(null, instance);
						break;
					}
				}
			}
		}

		private DataTable fillDataTable(string sqlquery, params SqlParameter[] sqlparams)
		{
			if ( _sqlConn == null )
				throw new NullReferenceException("Connection is null.");

			DataTable dt = new DataTable();
			SqlCommand cmd = new SqlCommand(sqlquery, _sqlConn);
			cmd.CommandType = CommandType.StoredProcedure;
			if ( sqlparams != null )
				cmd.Parameters.AddRange(sqlparams);

			using ( SqlDataAdapter da = new SqlDataAdapter(cmd) ) {
				da.Fill(dt);
			}
			return dt;
		}

		private void loadWorkflowInstances()
		{
			loadWorkflowInstances(true);
		}
		private void loadWorkflowInstances(bool showOptions)
		{
			if ( tstxtWfName.Text == null ) tstxtWfName.Text = "";
			if ( showOptions ) ShowOptions(true);
			if ( string.IsNullOrEmpty(_connectionString) ) return;
			TrackingQuery query = new TrackingQuery(_connectionString);
			TrackingQueryOptions options = new TrackingQueryOptions();
			options.StatusMinDateTime = dtpMinWfStart.Checked ? dtpMinWfStart.Value : DateTime.MinValue;
			options.StatusMaxDateTime = dtpMaxWfStart.Checked ? dtpMaxWfStart.Value : DateTime.MaxValue;
			WorkflowStatusEx status = (WorkflowStatusEx)tscmbWfStatus.SelectedItem;
			options.WorkflowStatus = status == WorkflowStatusEx.All ? (WorkflowStatus?)null : (WorkflowStatus)( (int)status );
			options.WorkflowName = tstxtWfName.Text;
			_wfInstances.Clear();
			_actInstances.Clear();
			_processList.WorkflowInstances.DataSource = null;
			IList<TrackingWorkflowInstance> list = null;
			this.TopLevelControl.Refresh();
			try {

				list = query.GetWorkflows(options);
			} catch ( Exception ex ) {
				MessageBox.Show(string.Format("An error occured while receiving tracked workflows.{0}{1}", Environment.NewLine, ex.Message),
					"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}
			this.TopLevelControl.Refresh();
			foreach ( TrackingWorkflowInstance item in list ) {
				_wfInstances.Add(new TrackedProcessInstance(item));
			}
			_processList.WorkflowInstances.DataSource = _wfInstances;
			this.TopLevelControl.Refresh();
		}

		/// <summary>
		/// Allows the user to select an assembly.
		/// </summary>
		/// <param name="fullname">The fullname of the assembly.</param>
		/// <param name="useIgnoreDllResolve">if set to <c>true</c> use the ignoreDllresolve list.</param>
		/// <param name="suppressQuestion">if set to <c>true</c> suppress the question/information if the user wants to select the file.</param>
		/// <returns></returns>
		private Assembly openAssembly(string fullname, bool useIgnoreDllResolve, bool suppressQuestion)
		{
			if ( useIgnoreDllResolve && _ignoreDllResolve.Contains(fullname) ) return null;
			Assembly assembly = null;
			//int retries = 0;
			bool retry;
			AssemblyName asmName = new AssemblyName(fullname);
			string displayName = string.Format("'{0}' (Version: {1})", asmName.Name, asmName.Version);
			DialogResult yesNoResult = DialogResult.Yes;
			if ( !suppressQuestion )
				yesNoResult = MessageBox.Show(
					string.Format("Before the composite {1} can be tracked using the graphical view, the location of the composite's DLL must be located. This DLL is located in the \"Bin\" directory of the published web service directory. Would you like to locate this file now?{0}{0}Note: If the location of the DLL is not specified, the composite can still be tracked without the graphical view.", Environment.NewLine, displayName),
					"Assembly Load Error", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

			if ( yesNoResult == DialogResult.Yes ) {
				do {
					retry = false;

					OpenFileDialog dlg = new OpenFileDialog();
					dlg.Title = string.Format("Open file containing assembly '{0}'.", fullname);
					dlg.Filter = "All Files (*.dll;*.exe)|*.dll;*.exe|Direct Link Library (*.dll)|*.dll|Executable File (*.exe)|*.exe";
					dlg.CheckFileExists = true;
					dlg.AutoUpgradeEnabled = true;
					DialogResult openResult = dlg.ShowDialog();
					foreach ( string file in dlg.FileNames ) {
						assembly = Assembly.LoadFile(file);
						if ( assembly != null && assembly.FullName == fullname ) break;
					}
					//retries++;
					if ( assembly == null || assembly.FullName != assembly.FullName ) {
						if ( openResult != DialogResult.Cancel && !suppressQuestion ) {
							DialogResult result = MessageBox.Show(
								string.Format("The selected file does not contain the composite '{1}' could not be found.{0}Do you want to retry selecting another file or do you want to continue in text only mode without loading the file (Cancel)!", Environment.NewLine, displayName),
								"Assembly Load Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Warning);
							if ( result == DialogResult.Retry ) retry = true;
						}
					}

				} while ( retry );
			}
			_ignoreDllResolve.Add(fullname);
			return assembly;
		}

		private void selectActivity(TrackedActivityInstance activityTrackingRecord)
		{
			if ( _loader == null ) return;

			if ( _loader.RootActivity != null ) {
				ISelectionService selectionService = _surface.GetService(typeof(ISelectionService)) as ISelectionService;
				IReferenceService referenceService = _surface.GetService(typeof(IReferenceService)) as IReferenceService;
				Activity activityComponent = _loader.RootActivity.GetActivityByName(activityTrackingRecord.Name);
				if ( activityComponent != null ) {
					selectionService.SetSelectedComponents(new IComponent[] { activityComponent });
				}
			}
			this.TopLevelControl.Refresh();
			_details.LoadDetails(null, activityTrackingRecord);
			_businessObjectView.LoadActivity(activityTrackingRecord);
		}

		private void showWorkflow(TrackedProcessInstance sqlTrackingWorkflowInstance)
		{
			Initialize();

			Dictionary<string, ActivityStatusInfoCollection> activityStatusListValue = new Dictionary<string, ActivityStatusInfoCollection>();
			for ( int index = sqlTrackingWorkflowInstance.Instance.ActivityEvents.Count; index >= 1; index-- ) {
				ActivityTrackingRecord activityTrackingRecord = sqlTrackingWorkflowInstance.Instance.ActivityEvents[index - 1];
				ActivityStatusInfo latestActivityStatus = new ActivityStatusInfo(activityTrackingRecord.QualifiedName, activityTrackingRecord.ExecutionStatus.ToString());
				if ( !activityStatusListValue.ContainsKey(activityTrackingRecord.QualifiedName) ) {
					ActivityStatusInfoCollection infos = new ActivityStatusInfoCollection(5); // maybe 3 or 4 would be enough?
					infos.Add(latestActivityStatus);
					activityStatusListValue.Add(activityTrackingRecord.QualifiedName, infos);
				} else {
					activityStatusListValue[activityTrackingRecord.QualifiedName].Add(latestActivityStatus);
				}
			}
			IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost));
			if ( host == null )
				return;

			if ( _workflowView.ContainsView(_view) ) {
				_workflowView.RemoveView(_view);
				_view.Dispose();
				_view = null;
			}
			if ( sqlTrackingWorkflowInstance.Instance.WorkflowDefinition != null ) {
				_loader.WorkflowDefinition = sqlTrackingWorkflowInstance.Instance.WorkflowDefinition;
				_surface.BeginLoad(_loader);

				IRootDesigner rootDesigner = host.GetDesigner(host.RootComponent) as IRootDesigner;
				if ( rootDesigner != null ) {
					_view = rootDesigner.GetView(ViewTechnology.Default) as WorkflowView;
				}

				IDesignerGlyphProviderService glyphService = _surface.GetService(typeof(IDesignerGlyphProviderService)) as IDesignerGlyphProviderService;
				WorkflowMonitorDesignerGlyphProvider glyphProvider = new WorkflowMonitorDesignerGlyphProvider(activityStatusListValue);
				glyphService.AddGlyphProvider(glyphProvider);

				_view.Dock = DockStyle.Fill;
				( (IDesignerLoaderHost)host ).EndLoad(host.RootComponentClassName, true, null);

				_workflowView.AddView(_view);
				_view.BringToFront();
				this.TopLevelControl.Refresh();
			} else if ( !_details.Visible ) {
				toggleDetails(true);
			}
			this.TopLevelControl.Refresh();
			_actInstances.Clear();
			sqlTrackingWorkflowInstance.Instance.LoadActivityEvents();
			foreach ( ActivityTrackingRecord record in sqlTrackingWorkflowInstance.Instance.ActivityEvents.ToArray() ) {
				_actInstances.Add(new TrackedActivityInstance(record));
			}
			_activityList.ActivityInstances.DataSource = _actInstances;

			this.TopLevelControl.Refresh();
			_details.LoadDetails(sqlTrackingWorkflowInstance, _actInstances.Count == 0 ? null : _actInstances[0]);
		}

		private void toggleDetails(bool show)
		{
			if ( show ) {
				_details.Show(_workflowView.Pane, DockAlignment.Bottom, 0.4);
			} else {
				_details.Hide();
			}
			detailsToolStripMenuItem.Checked = show;
			tsbtnDetails.Checked = show;
			this.TopLevelControl.Refresh();
		}

		private void toggleBobjView(bool show)
		{
			if ( show ) {
				_businessObjectView.Show(_workflowView.Pane, DockAlignment.Bottom, 0.4);
			} else {
				_businessObjectView.Hide();
			}
			businessObjectsToolStripMenuItem.Checked = show;
			tsbtnShowBobjView.Checked = show;
			this.TopLevelControl.Refresh();
		}

		#endregion Methods

		#endregion Private Members

		#region Nested Types

		[DebuggerDisplay("Activity = {Name}, Status = {Status}")]
		private class ActivityStatusInfo
		{
			#region Initialization

			internal ActivityStatusInfo(string name, string status)
			{
				this.nameValue = name;
				this.statusValue = status;
			}

			#endregion Initialization

			#region Internal Members

			#region Properties

			internal string Name
			{
				get { return nameValue; }
			}

			internal string Status
			{
				get { return statusValue; }
			}

			#endregion Properties

			#endregion Internal Members

			#region Private Members

			#region Fields

			private string nameValue;
			private string statusValue;

			#endregion Fields

			#endregion Private Members
		}
		private class ActivityStatusInfoCollection : List<ActivityStatusInfo>
		{
			public ActivityStatusInfoCollection()
				: base()
			{

			}
			public ActivityStatusInfoCollection(int capacity)
				: base(capacity)
			{

			}
			public ActivityStatusInfoCollection(IEnumerable<ActivityStatusInfo> collection)
				: base(collection)
			{

			}

			/// <summary>
			/// Gets the name of the Activity associated with the collection of ActivityStatus.
			/// </summary>
			/// <value>The name.</value>
			public string Name
			{
				get { return this.Count == 0 ? null : this[0].Name; }
			}

			/// <summary>
			/// Determines whether the collection contains the specified status.
			/// </summary>
			/// <param name="status">The status.</param>
			/// <returns>
			/// 	<c>true</c> if the collection contains the specified status; otherwise, <c>false</c>.
			/// </returns>
			public bool Contains(string status)
			{
				foreach ( ActivityStatusInfo info in this ) {
					if ( info.Status == status ) return true;
				}
				return false;
			}
		}

		private abstract class StatusGlyph : DesignerGlyph
		{
			protected abstract Bitmap StatusIcon { get; }

			public override Rectangle GetBounds(ActivityDesigner designer, bool activated)
			{
				Rectangle imageBounds = Rectangle.Empty;
				Image image = this.StatusIcon;
				if ( image != null ) {
					Size glyphSize = WorkflowTheme.CurrentTheme.AmbientTheme.GlyphSize;
					imageBounds.Location = new Point(designer.Bounds.Right - glyphSize.Width / 2, designer.Bounds.Top - glyphSize.Height / 2);
					imageBounds.Size = glyphSize;
				}
				return imageBounds;
			}
			protected override void OnPaint(Graphics graphics, bool activated, AmbientTheme ambientTheme, ActivityDesigner designer)
			{
				Bitmap bitmap = this.StatusIcon;
				bitmap.MakeTransparent(Color.FromArgb(0, 255, 255));
				if ( bitmap != null )
					graphics.DrawImage(bitmap, GetBounds(designer, activated), new Rectangle(Point.Empty, bitmap.Size), GraphicsUnit.Pixel);
			}
		}

		private sealed class CompletedGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.complete; }
			}
		}

		private sealed class ExecutingGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.png_executing; }
			}
		}

		private sealed class FaultedGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.png_cancel; }
			}
		}

		private sealed class AbortedGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.png_cancel; }
			}
		}

		private sealed class CancelledGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.png_cancel; }
			}
		}

		private sealed class TerminatedGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.png_cancel; }
			}
		}

		private sealed class SuspendedGlyph : StatusGlyph
		{
			protected override Bitmap StatusIcon
			{
				get { return Resources.png_pause; }
			}
		}

		private class MemberCreationService : IMemberCreationService
		{
			#region Public Members

			#region Methods

			void IMemberCreationService.CreateEvent(string className, string eventName, Type eventType, AttributeInfo[] attributes, bool emitDependencyProperty)
			{
			}

			// Designer host requires an IMemberCreationService - we don't need this functionality
			// so all of the methods are blank
			void IMemberCreationService.CreateField(string className, string fieldName, Type fieldType, Type[] genericParameterTypes, MemberAttributes attributes, CodeSnippetExpression initializationExpression, bool overwriteExisting)
			{
			}

			void IMemberCreationService.CreateProperty(string className, string propertyName, Type propertyType, AttributeInfo[] attributes, bool emitDependencyProperty, bool isMetaProperty, bool isAttached, Type ownerType, bool isReadOnly)
			{
			}

			void IMemberCreationService.RemoveEvent(string className, string eventName, Type eventType)
			{
			}

			void IMemberCreationService.RemoveProperty(string className, string propertyName, Type propertyType)
			{
			}

			void IMemberCreationService.ShowCode(Activity activity, string methodName, Type delegateType)
			{
			}

			void IMemberCreationService.ShowCode()
			{
			}

			void IMemberCreationService.UpdateBaseType(string className, Type baseType)
			{
			}

			void IMemberCreationService.UpdateEvent(string className, string oldEventName, Type oldEventType, string newEventName, Type newEventType, AttributeInfo[] attributes, bool emitDependencyProperty, bool isMetaProperty)
			{
			}

			void IMemberCreationService.UpdateProperty(string className, string oldPropertyName, Type oldPropertyType, string newPropertyName, Type newPropertyType, AttributeInfo[] attributes, bool emitDependencyProperty, bool isMetaProperty)
			{
			}

			void IMemberCreationService.UpdateTypeName(string oldClassName, string newClassName)
			{
			}

			#endregion Methods

			#endregion Public Members
		}

		private class WorkflowMonitorDesignerGlyphProvider : IDesignerGlyphProvider
		{
			#region Initialization

			internal WorkflowMonitorDesignerGlyphProvider(Dictionary<string, ActivityStatusInfoCollection> activityStatusList)
			{
				this.activityStatusList = activityStatusList;
			}

			#endregion Initialization

			#region Public Members

			#region Methods

			ActivityDesignerGlyphCollection IDesignerGlyphProvider.GetGlyphs(ActivityDesigner activityDesigner)
			{
				ActivityDesignerGlyphCollection glyphList = new ActivityDesignerGlyphCollection();

				foreach ( ActivityStatusInfoCollection activityStatus in activityStatusList.Values ) {
					if ( activityStatus.Count == 0 ) continue;
					if ( activityStatus.Name == activityDesigner.Activity.QualifiedName ) {
						if ( activityStatus.Contains("Faulting") ) {
							glyphList.Add(new FaultedGlyph());
						} else if ( activityStatus.Contains("Closed") ) {
							glyphList.Add(new CompletedGlyph());
						} else if ( activityStatus.Contains("Executing") ) {
							glyphList.Add(new ExecutingGlyph());
						} else {
						}
					}
				}

				return glyphList;
			}

			#endregion Methods

			#endregion Public Members

			#region Private Members

			#region Fields

			private Dictionary<string, ActivityStatusInfoCollection> activityStatusList;

			#endregion Fields

			#endregion Private Members
		}

		#endregion Nested Typesx
	}

	#region Enumerations

	public enum WorkflowStatusEx
	{
		All = -1,
		Running,
		Completed,
		Suspended,
		Terminated,
		Created
	}

	#endregion Enumerations
}